什么是 CD 管道?一文告诉你如何借助Kubernetes、Ansible和Jenkins创建CD管道!
CI/CD(CI全名Continuous Integration,持续集成;CD全名Continuous Deployment,持续部署)这个术语常常和DevOps、Agile、Scrum以及Kanban、自动化等其他术语一起出现。
有时,人们只将它看作是工作流的一部分,而没有真正理解它是什么或采用它的意义是什么。年轻的DevOps工程师经常将CI/CD视作理所当然的事情,他们可能没有见过“传统的”软件发布周期,因此,get不到CI/CD的好处。
CI/CD代表持续集成、持续交付和部署。未实现CI/CD的团队在创建新软件产品时必须经历以下几个阶段:
产品经理(代表客户的利益)提供产品应该具有的特性和应该实现的行为。该环节必须尽可能全面和具体。 开发人员借助业务分析师的帮助,通过编写代码,运行单元测试并将结果提交到版本控制系统(例如git)。 开发阶段结束后,项目将被转移到QA(Quality Assurance,质量保证)。针对产品运行几个测试,比如用户验收测试、集成测试、性能测试等等。在此期间,在QA阶段完成之前,不会对代码库进行任何更改。如果有任何bug,他们会返还给开发人员进行修复,然后修改后的产品将被再次交给QA。 QA结束后,操作团队会将代码部署到生产环境中。
正在运行的Jenkins实例。可以是云实例、虚拟机、裸机或docker容器。它必须能够从网络上进行公开访问,以便存储库可以通过webhook连接到Jenkins。
镜像注册表:你可以使用Docker Registry,这是一种基于云的产品,如ECR或GCR,甚至也可以使用自定义注册表。
步骤一:应用文件
由于我们要构建一个CD管道,所以应该进行一些测试。我们的代码非常简单,只需要一个测试用例即可,确保我们在点击根URL时能够收到正确的字符串。在相同目录中创建一个名为main_test.go的新文件,并添加以下内容:
这没有什么特别之处。只是一个使用NodePort作为其类型的服务。它将监听任何集群节点的IP地址上的32000端口。传入的连接将中继到8080端口上的吊舱(pod)。内部通信方面,服务将监听80端口。
Ansible已经包含了用于处理与Kubernetes API服务器通信的k8s模块。因此,我们不需要安装kubectl,但是我们需要一个有效的kubeconfig文件来连接到集群(稍后会详细介绍)。我们来快速浏览一下playbook:
k8s模块: https://docs.ansible.com/ansible/latest/modules/k8s_module.html
kubectl: https://kubernetes.io/docs/reference/kubectl/overview/
playbook的主要功能是用于将服务和资源部署到集群。
因为我们需要在执行时将数据动态地注入到定义文件中,所以需要使用我们的定义文件作为模板,其中可以从外部提供变量。
为此,Ansible提供了查找功能,你可以在其中传递有效的YAML文件作为模板。Ansible支持多种将变量注入到模板的方法。在本特定实验中,我们将使用命令行方法。
步骤二:安装Jenkins、Ansible和Docker
现在,我们可以安装Ansible,并通过它来自动部署一个Jenkins服务器和Docker运行时环境。我们还需要安装openshift Python模块以启用与Kubernetes的Ansible连接。
Ansible的安装过程非常简单,只需安装Python,然后使用pip安装Ansible就可以了:
1. 登录到Jenkins实例。
2. 安装Python 3、Ansible和openshift模块:
sudo apt update && sudo apt install -y python3 && sudo apt install -y python3-pip && sudo pip3 install ansible && sudo pip3 install openshift
3. 默认情况下,pip会将二进制文件安装在用户主文件夹中的一个隐藏目录下。我们需要将此目录添加到$PATH变量中,以便轻松调用命令:
echo "export PATH=$PATH:~/.local/bin" >> ~/.bashrc && . ~/.bashrc
ansible-galaxy install geerlingguy.jenkins
5. 安装Docker角色:
ansible-galaxy install geerlingguy.docker
6. 创建一个playbook.yaml文件并添加以下内容:
ansible-playbook playbook.yaml.
这里要注意,我们实例使用的公共IP地址作为Jenkins使用的主机名。如果你使用的是DNS,那么可能需要替换成实例的DNS名称。另外,请注意,在运行playbook之前,必须在防火墙上启用8080端口 (如果有的话)。
8. 几分钟后,Jenkins应该就安装好了。你可以通过导航到计算机的IP地址(或者DNS名称)并指定8080端口来进行检查:
步骤04:创建Jenkins Pipeline 作业
创建一个新的Jenkins作业并选择管道类型。作业设置如下所示:
我们更改的设置是:
我们使用Poll SCM作为构建触发器,此设置将会指导Jenkins定期检查Git存储库(按*****指示的每分钟检查一次)。如果仓库自上次poll以来已经更改过,那么将触发作业。
在管道本身,我们指定了存储库URL和凭据。分支是master。
在本实验中,我们将作业的所有代码添加到一个Jenkinsfile中,该文件与代码存储在相同的存储库中。本文稍后将讨论该Jenkinsfile。
步骤五:为GitHub和Docker Hub配置Jenkins凭据
转到/credentials/store/system/domain/_/newCredentials并将凭据添加到两个目标中。确保提供有效的ID和描述,因为稍后将引用它们:
/credentials/store/system/domain/_/newCredentials:
http://35.238.224.64:8080/credentials/store/system/domain/_/newCredentials
步骤六:创建Jenkinsfile
Jenkinsfile指导Jenkins如何构建、测试、docker化、发布并交付我们的应用程序。我们的Jenkinsfile如下所示:
pipeline {
agent any
environment {
registry = "magalixcorp/k8scicd"
GOCACHE = "/tmp"
}
stages {
stage('Build') {
agent {
docker {
image 'golang'
}
}
steps {
// Create our project directory.
sh 'cd ${GOPATH}/src'
sh 'mkdir -p ${GOPATH}/src/hello-world'
// Copy all files in our Jenkins workspace to our project directory.
sh 'cp -r ${WORKSPACE}/* ${GOPATH}/src/hello-world'
// Build the app.
sh 'go build'
}
}
stage('Test') {
agent {
docker {
image 'golang'
}
}
steps {
// Create our project directory.
sh 'cd ${GOPATH}/src'
sh 'mkdir -p ${GOPATH}/src/hello-world'
// Copy all files in our Jenkins workspace to our project directory.
sh 'cp -r ${WORKSPACE}/* ${GOPATH}/src/hello-world'
// Remove cached test results.
sh 'go clean -cache'
// Run Unit Tests.
sh 'go test ./... -v -short'
}
}
stage('Publish') {
environment {
registryCredential = 'dockerhub'
}
steps{
script {
def appimage = docker.build registry + ":$BUILD_NUMBER"
docker.withRegistry( '', registryCredential ) {
appimage.push()
appimage.push('latest')
}
}
}
}
stage ('Deploy') {
steps {
script{
def image_id = registry + ":$BUILD_NUMBER"
sh "ansible-playbook playbook.yml --extra-vars \"image_id=${image_id}\""
}
}
}
}
}
文件构建起来比看上去容易。管道基本上包含四个阶段: 1. 在Build阶段构建Go二进制,并且确保在构建过程中没有任何错误。 2. 在Test阶段应用简单的UAI测试来确保应用程序按预期工作。 3. 在Publish阶段构建Docker镜像,并将其推送到注册表。此后,其可供任何环境使用。 4. 在Deploy阶段调用Ansible来联系Kubernetes并应用定义文件。 现在,我们来讨论一下此Jenkinsfile的关键部分。 前两个阶段大致相似。它们都是用了golang Docker镜像来构建应用程序。让阶段在已经准备好所有必需的构建和测试工具的Docker容器中运行始终是一个好习惯。另一个选择是在主服务器上或者从服务器上安装这些工具。当你需要针对不同的工具版本进行测试时,问题就来了。例如,我们可能希望使用Go 1.9构建和测试我们的代码,因为我们的应用程序还没有准备好使用最新版本的Golang。镜像中包含所有内容,因此更改版本甚至镜像类型就变得像更改字符串一样简单。 Publish阶段(从第42行开始)首先指定一个环境变量,该变量将在后面的步骤中使用。该变量指向在先前步骤中添加到Jenkins的Docker Hub凭据的ID。 第48行:我们使用docker插件来构建镜像。它默认在注册表中使用Dockerfile,并将构建编号添加为镜像标签。当你需要确定哪个Jenkins构建是当前正在运行的容器的源代码时,这就变得非常重要。 第49-51行:镜像构建成功之后,我们使用构建编号将其推入Docker Hub。此外,我们将“最新的”标签添加到镜像中(第二个标签),这样一来,如果用户需要,就可以在不指定构建编号的情况下提取镜像。 第56-60行: 在部署阶段,我们将部署和服务定义文件应用到集群。我们使用之前讨论过的playbook来调用Ansible。需要注意,我们将image_id作为命令行变量传递。此值将自动替换部署文件中的镜像名称。git add *
2. 提交更改:
git commit -m "Initial commit"
git push
7. 现在,让我们向应用程序发起一个HTTP请求:
可以看到,我们的应用程序运行正常。下面,让我们在代码中故意犯一个错误,并确保管道不会将错误代码发送到目标环境:
将应该显示的消息更改为“Hello World!”(我们将每个单词的第一个字母大写,并在后面加上感叹号)。因为我们的客户可能不希望消息以这种方式显示,所以管道应该在Test测试阶段停止。 首先,我们进行了更改。现在,main.go文件应如下所示:接下来,让我们提交并推送代码:
回到Jenkins,我们可以看到最后一次构建失败了:
通过单击失败的作业,我们可以看到其失败的原因:
该错误代码永远不会到达目标环境。
CI/CD是所有遵循Agile方法的现代环境的组成部分。
通过管道,你能够确保代码从版本控制系统到目标环境(testing/staging/production/etc.)的平稳过渡,同时应用所有必要的测试和质量控制实践。
在本文中,我们进行了真实的实验,构建了一个持续交付管道来部署Golang应用程序。
通过Jenkins,我们能够从存储库中提取代码,使用相关的Docker镜像对其进行构建和测试。
接下来,我们对应用程序进行Docker化并将其推送到Docker Hub——因为它通过了我们的测试。
最后,我们使用Ansible将应用程序部署到运行Kubernetes的目标环境中。
使用Jenkins管道和Ansible令更改工作流变得非常简单和灵活,几乎不会产生什么摩擦问题。例如,我们可以在Test阶段中添加更多的测试,可以更改用于构建和测试代码的Go版本,还可以使用更多的变量来更改部署和服务中的其他方面。
最棒的一点是我们使用了Kubernetes部署,这能够确保在更改容器镜像时,应用程序的停机时间为0。因为Deployments在默认情况下使用滚动更新方法来终止和重新创建容器。只有当新容器启动并且运行状况良好时,Deployment才会终止旧容器。
原文:https://hackernoon.com/how-to-create-a-cd-pipeline-with-kubernetes-ansible-and-jenkins-i6c03yp2
与时间赛跑:微盟的数据恢复为什么需要这么长时间 0.052秒打开100GB数据?这个Python开源库这样做数据分析
GitHub 一周热点速览:手撕 LeetCode 一日 star 破两千
Libra为何而生?Facebook为何要给 Libra创建Move语言?Calibra技术负责人给出了回答
当数据处理做不到实时,应该怎么办?